/**
  ***********************************************************************************************************
  * @file           : bsp_uart_class.cpp
  * @brief          : 串口类的源文件
  ***********************************************************************************************************
  * @interface
  * 用   rx_mode_config  来设置串口接收的模式
  * 用   acquire_data    来获取当前读缓冲区内的数据
  * 用   acquire_data_length 来获取当前读缓冲区内数据的长度,特别是不定长接收模式
  * 用   wait_for_new_data   来对新数据进行等待,注意只能在RTOS任务内调用,会对任务进行阻塞
  ***********************************************************************************************************
  */

#include "string.h"
#include "stdlib.h"
#include "bsp_uart_class.h"

static void Stop_UART_Receive_For_Restart(UART_HandleTypeDef *huart);
/**
 * @brief 安全停止UART接收并重置状态，便于直接重新调用HAL接收函数
 * @param huart UART句柄指针
 * @note 此函数会停止当前接收并将UART状态重置，之后可以直接调用HAL_UART_Receive_*系列函数
 */
static void Stop_UART_Receive_For_Restart(UART_HandleTypeDef *huart)
{
    /* 中止任何正在进行的中断接收 */
    if (huart->RxState != HAL_UART_STATE_READY) {
        HAL_UART_AbortReceive(huart);
    }
    /* 对于DMA模式，停止DMA传输 */
    if (huart->hdmarx != NULL) {
        HAL_UART_DMAStop(huart); // 停止DMA接收
    }
    /* 禁用UART接收相关中断 */
    __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); // 接收中断
    __HAL_UART_DISABLE_IT(huart, UART_IT_IDLE); // 空闲中断:cite[4]
    __HAL_UART_DISABLE_IT(huart, UART_IT_PE);   // 奇偶错误中断
    __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);  // 错误中断
    /* 清除可能挂起的中断标志 - 使用正确的HAL库宏 */
    // 清除空闲中断标志:cite[4]:cite[6]
    __HAL_UART_CLEAR_IDLEFLAG(huart);
    // 清除溢出错误(ORE)标志 - 通过读SR和DR:cite[1]:cite[7]
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE)) {
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_ORE);
    }
    // 清除其他错误标志:cite[7]
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_FE)) {
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_FE);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_NE)) {
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_NE);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_PE)) {
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_PE);
    }
    /* 重置UART接收状态为就绪状态 */
    huart->RxState = HAL_UART_STATE_READY;
}


/**
 * @brief 配置接收缓冲区大小
 * @param   size    缓冲区的大小      @包多长就配成多长(包括包头和包尾)
 */
void Uart::rx_buf_config(uint8_t size)
{
    //先释放内存
    //检查内存是否已经分配，如已分配就释放
    if (this->rx_buf[0] != NULL) {
        free(this->rx_buf[0]);  this->rx_buf[0] = NULL;
    }
    if (this->rx_buf[1] != NULL) {
        free(this->rx_buf[1]);  this->rx_buf[1] = NULL;
    }
    //size为0时
    if(size == 0)
    {
        //如果模式不是DISEN就报错
        if(this-> mode != uart_e::DISEN) {
            this-> error_status = 3;
        }
    }
    //size非0时就分配内存
    else
    {
        //分配内存
        this->rx_buf[0] = (uint8_t *) malloc(size * sizeof(uint8_t));
        this->rx_buf[1] = (uint8_t *) malloc(size * sizeof(uint8_t));
        //分配内存失败时,报错
        if (rx_buf[0] == NULL || rx_buf[1] == NULL) {
            this->error_status = 1;
        }
    }
}

/**
 * @brief 配置串口类模式
 * @param   type        需要配置的模式     @Uart::uart_e内的内容
 * @param   size        缓冲区大小         @给多少一个包就是多长,包含包头和包尾
 * @param   _header     包头              @使用包头模式才有用，其他模式随便给
 * @param   _tail       包尾              @使用包头包尾模式才有用，其他模式随便给
 */
void Uart::rx_mode_config(const Uart::uart_e _mode, const uint8_t size,
                          uint8_t _header,  uint8_t _tail)
{
    //先停止串口接收
    Stop_UART_Receive_For_Restart(this-> handle);
		//清除或配置一些数据和标志
	  {    
				this-> mode = _mode;				//注意要先变更模式,再进行缓冲区大小管理,不然切换DISEN模式且size为0时就会报错
        this-> header = _header;
        this-> tail = _tail;
        this-> rx_buf_flag = 0;
        this-> rx_status = 0;
    }
	
    //检查是否需要重新分配缓冲区大小
    if(size != this-> buf_size){
        this-> buf_size = size;
        rx_buf_config(size);
    }


    switch (_mode)
    {
        //原生模式
        case uart_e::DISEN:  { break; } //停用接收
        case uart_e::NORMAL_IT: {
            HAL_UART_Receive_IT(this-> handle, this->rx_buf[0], this->buf_size);break;
        }
        case uart_e::DMA_IT: {
            HAL_UART_Receive_DMA(this-> handle, this->rx_buf[0], this->buf_size);break;
        }
        case uart_e::NORMAL_toIDLE_IT: {
            HAL_UARTEx_ReceiveToIdle_IT(this-> handle, this->rx_buf[0], this->buf_size);break;
        }
        case uart_e::DMA_toIDLE_IT: {
            HAL_UARTEx_ReceiveToIdle_DMA(this-> handle, this->rx_buf[0], this->buf_size);break;
        }

        //通过软件实现的根据包头包尾接收模式
        case uart_e::DMA_IT_HEADED: {
            HAL_UART_Receive_DMA(this-> handle, this->rx_buf[0], 1);    //先捕捉包头
            break;
        }
        case uart_e::DMA_IT_HEADED_TAIL: {
            HAL_UART_Receive_DMA(this-> handle, this->rx_buf[0], 1);    //先捕捉包头
            break;
        }
        default:
            break;
    }
}

/**
 * @brief 构造函数
 * @param   hand    此类指向的串口外设句柄
 * @param   size    串口接收缓冲区的大小   @应包含包头和包尾的长度
 */
Uart::Uart(UART_HandleTypeDef* hand,uint8_t size):
        handle(hand), buf_size(size)
{
    //给双缓冲区分配内存
    rx_buf_config(this-> buf_size);
    //创建RTOS信号量
    osSemaphoreAttr_t rx_sem_attr = { .name = "uart_rx_sem" }; // 信号量属性
    this->rx_sem = osSemaphoreNew(1, 0, &rx_sem_attr);
    //信号量创建失败
    if(rx_sem == NULL) {
        error_status = 2;
    }
}

Uart::~Uart()
{
    if(this->rx_buf[0] != NULL) {
        free(rx_buf[0]);    rx_buf[0] = NULL;
    }
    if(this->rx_buf[1] != NULL) {
        free(rx_buf[1]);    rx_buf[1] = NULL;
    }
}


/**
 * @brief 接收数据处理,在HAL库中断回调里面被调用
 * @param   size    数据长度        @如果是定长接收,那么传的是类缓冲区的大小.
 *                                 @如果是串口闲时中断,传的是实际接收数据的长度.
 */
void Uart::rx_process(const uint8_t _size)
{
    /* 处理定长和不定长模式 */
    if (mode == uart_e::NORMAL_IT || mode == uart_e::DMA_IT ||
        mode == uart_e::NORMAL_toIDLE_IT ||  mode == uart_e::DMA_toIDLE_IT)
    {
        // 通用处理流程
        rx_data_length[rx_buf_flag] = _size;
        osSemaphoreRelease(rx_sem);
        rx_buf_flag = 1 - rx_buf_flag;

        // 模式特定重启接收
        if (mode == uart_e::NORMAL_IT) {
            HAL_UART_Receive_IT(handle, rx_buf[rx_buf_flag], buf_size);
        } else if (mode == uart_e::DMA_IT) {
            HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag], buf_size);
        } else if (mode == uart_e::NORMAL_toIDLE_IT) {
            HAL_UARTEx_ReceiveToIdle_IT(handle, rx_buf[rx_buf_flag], buf_size);
        } else {
						HAL_UARTEx_ReceiveToIdle_DMA(handle, rx_buf[rx_buf_flag], buf_size);
				}
    }
    /* 处理包头模式 */
    else if (mode == uart_e::DMA_IT_HEADED)
    {
        if (rx_status == 0) // 接收包头
        {
            if (rx_buf[rx_buf_flag][0] == header) {
                HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag] + 1, buf_size - 1);
                rx_status = 1;  // 切换到接收包体状态
            } else {
                HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag], 1);
            }
        }
        else if (rx_status == 1) // 接收包体
        {
            rx_data_length[rx_buf_flag] = buf_size;
            osSemaphoreRelease(rx_sem);
            rx_buf_flag = 1 - rx_buf_flag;
            rx_status = 0;  // 重置为接收包头状态
            HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag], 1);
        }
    }
    /* 处理包头包尾模式 */
    else if (mode == uart_e::DMA_IT_HEADED_TAIL)
    {
        switch (rx_status)
        {
            case 0: // 接收包头
            {
                if (rx_buf[rx_buf_flag][0] == header) {
                    HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag] + 1, buf_size - 2);
                    rx_status = 1;  // 切换到接收包体状态
                } else {
                    HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag], 1);
                }
                break;
            }
            case 1: // 接收包体
            {
                HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag] + buf_size - 1, 1);
                rx_status = 2;  // 切换到接收包尾状态
                break;
            }
            case 2: // 接收并验证包尾
            {
                if (rx_buf[rx_buf_flag][buf_size - 1] == tail)
                {
                    rx_data_length[rx_buf_flag] = buf_size;
                    osSemaphoreRelease(rx_sem);
                    rx_buf_flag = 1 - rx_buf_flag;  // 仅在包尾匹配时切换缓冲区
                }
                // 无论包尾是否匹配都重置状态机
                rx_status = 0;
                HAL_UART_Receive_DMA(handle, rx_buf[rx_buf_flag], 1);
                break;
            }
        }
    }
}


/**
 * @brief   从读缓冲区中将数据拷贝到传入指针指向的内存里
 * @param[out]   des    指向接收数据的头字节的指针
 * @param       size    需要拷贝的字节数        @若大于缓冲区的大小,则也只将缓冲区所有的数据拷贝过去
 * @note       调用前请结合 acquire_data_length 确定所要拷贝字节数,特别是不定长模式
 */
void Uart::acquire_data(uint8_t* des, uint8_t size)
{
    //检测size大小
    if (size <= 0)return;
    if (size > this-> buf_size) size = this-> buf_size;
    //进行拷贝
    memcpy(des, this-> rx_buf[1 - this-> rx_buf_flag],size);
}

/**
 * @brief   获取读缓冲区中接收的数据长度
 * @retval  数据长度
 */
uint8_t Uart::acquire_data_length()
{
    return this-> rx_data_length[1 - this-> rx_buf_flag];
}

/**
 * @brief   检查等待新数据的到来,会阻塞rtos任务,用于配合用户层的RTOS任务实现数据的接收
 * @param		wait_or_notWait			是否等待数据的到来,如果等待就一直等	@0:不等,	1:等
 * @retval	有新数据就返回	0	, 否则返回	1
 * @note    此函数只能在RTOS内调用,若wait_or_notWait乱传就默认不等
 */
uint8_t Uart::check_new_data(uint8_t wait_or_notWait)
{
	//不等待
		if(wait_or_notWait != 1)	
		{
				if(osSemaphoreAcquire(this-> rx_sem,0) == osOK) {
						return 0;
				} 
				else {
						return 1;
				}
				
		}
		//等待
		else
		{
				if(osSemaphoreAcquire(this-> rx_sem,osWaitForever) == osOK) {
							return 0;
				} 
				else {
						return 1;
				}
		}
}

